package com.baidu.mpks.filter;


import com.baidu.mpks.user.domain.User;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionKey;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.net.URLEncoder;
import java.util.Deque;
import java.util.LinkedList;

public class LoginMaxOneAccountFilter extends AccessControlFilter {
    private static final Logger log = LoggerFactory.getLogger(LoginMaxOneAccountFilter.class);
    private SessionManager sessionManager;
    private Cache<String, Deque<Serializable>> cache;
    private int maxSession;
    private boolean kickoutLast;

    public LoginMaxOneAccountFilter() {
    }

    public void setMaxSession(int maxSession) {
        this.maxSession = maxSession;
    }

    public void setKickoutLast(boolean kickoutLast) {
        this.kickoutLast = kickoutLast;
    }

    public void setCache(Cache<String, Deque<Serializable>> cache) {
        this.cache = cache;
    }

    public void setSessionManager(SessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        return false;
    }

    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        Subject subject = this.getSubject(request, response);
        if (!subject.isAuthenticated() && !subject.isRemembered()) {
            return true;
        } else {
            Session session = subject.getSession();
            String username = ((User)subject.getPrincipal()).getUserName();
            Serializable sessionId = session.getId();
            Deque<Serializable> deque = (Deque)this.cache.get(username);
            if (deque == null) {
                deque = new LinkedList();
            }

            if (!((Deque)deque).contains(sessionId) && session.getAttribute("kickout") == null) {
                ((Deque)deque).push(sessionId);
            }

            while(((Deque)deque).size() > this.maxSession) {
                Serializable kickoutSessionId;
                if (this.kickoutLast) {
                    kickoutSessionId = (Serializable)((Deque)deque).removeFirst();
                } else {
                    kickoutSessionId = (Serializable)((Deque)deque).removeLast();
                }

                try {
                    Session kickoutSession = this.sessionManager.getSession(new DefaultSessionKey(kickoutSessionId));
                    if (kickoutSession != null) {
                        kickoutSession.setAttribute("kickout", true);
                    }
                } catch (Exception var11) {
                    var11.printStackTrace();
                }
            }

            this.cache.put(username, deque);
            if (session.getAttribute("kickout") != null) {
                try {
                    subject.logout();
                } catch (Exception var10) {
                    log.warn("logout error: {}", var10.getMessage(), var10);
                }

                HttpServletResponse resp = (HttpServletResponse)response;
                resp.setStatus(401);
                resp.setHeader("login_error_msg", URLEncoder.encode("这个账号在其他的地方多次登录", "UTF-8"));
                return false;
            } else {
                return true;
            }
        }
    }
}
